/**
 * Implementacion de la clase SearchAlgorithm.
 */

#include <sstream>
#include "searchAlgorithm.hpp"

SearchAlgorithm::SearchAlgorithm(Logger *log)
{
	this->logger = log;
}
/*
 * priority = 1 -> velocidad
 * priority = 0 -> distancia
 */
int SearchAlgorithm::execute(Graph *graph, Node *nodeO , Node *nodeD, int priority)
{

	if(priority == 1)
	{
		/* Si la prioridad es de velocidad ordena de mayor a menor,
		 * por default ordena de menor a mayor.
		 */
		//this->pathList.setComparisonMode(0);
	}

	//By default all are -1
	nodeO->setTemporalWeight(0);

	this->searchPath(graph,nodeO,nodeD,priority);

	if(nodeD->getTemporalWeight() > 0 )
	{
		return 1;
	}
	else if (nodeD->getTemporalWeight() == 0)
	{
		return 0;
	}
	else
	{
		return -1;
	}



}

std::string SearchAlgorithm::getMinimumPath()
{
	return this->path;
}

/* Notas generales:
 *
 */
void SearchAlgorithm::searchPath(Graph *graph,Node *nodeO, Node *nodeD,int prior)
{

	if(nodeO->getId() == nodeD->getId())
	{
		std::string detail = "Camino encontrado";
		this->logger->reportSuccessMessage("SearchAlgorithm","searchPath",detail);
	}
	else
	{
		
		// Para cada arista del nodo
		ListIterator<Edge> it = nodeO->getEdgeList()->iterator();

		while(it.hasNext())
		{
			// Datos necesarios
			Edge *wayEdge = it.next();
			float weight;
			if(prior == 1)
			{
				weight = (wayEdge->getWeight().getLength()/wayEdge->getWeight().getVelocity());
			}
			else
			{
				weight = wayEdge->getWeight().getLength();
			}

			Node *destNode = graph->getNode(wayEdge->getDestinyId());

			// Verifico las marcas del nodo
			// Si estoy buscando el camino mas corto (prio = 0) reemplazo cuando la distancia el peso es menor
			// Si estoy buscando el camino mas rapido (prio = 1) reemplazo cuando la distancia el peso es mayor
			// Por defecto el temporal weight es -1
			if(
			    (destNode->getTemporalWeight() == -1)||
			    (destNode->getTemporalWeight() > nodeO->getTemporalWeight() + weight)
			  )
			{
				destNode->setTemporalWeight(nodeO->getTemporalWeight() + weight);
				destNode->setMinimunPathEdge(wayEdge);
				this->pathList.update(destNode);
				std::string detail = "marca en nodo: ";
							detail+= destNode->getId();
							detail+= ", peso = ";
							std::ostringstream buff;
							buff<<(nodeO->getTemporalWeight() + weight);
							detail+= buff.str();
							detail+= ", minimunPathEdge = ";
							detail+= wayEdge->getId();
							this->logger->reportSuccessMessage("SearchAlgorithm","searchPath",detail);
			}

		}

		Node *nextNode = this->pathList.popFirst();
		
		if (nextNode == NULL)
		{
			std::string detail = "Camino NO encontrado";
			this->logger->reportErrorMessage("SearchAlgorithm","searchPath",detail);
		}
		else
		{
			this->searchPath(graph,nextNode,nodeD,prior);
		}
	}
}

SearchAlgorithm::~SearchAlgorithm(){
	this->pathList.~List();
}

